package com.jdrx.sw.sewage.service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.jexl3.JexlBuilder;
import org.apache.commons.jexl3.JexlContext;
import org.apache.commons.jexl3.JexlEngine;
import org.apache.commons.jexl3.JexlScript;
import org.apache.commons.jexl3.MapContext;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.jdrx.sw.sewage.beans.entity.PointCalculationRulePO;
import com.jdrx.sw.sewage.common.util.LocalDateTimeUtils;
import com.jdrx.sw.sewage.dao.DeviceTimeDataDAO;
import com.jdrx.sw.sewage.dao.GatherDevPointDAO;
import com.jdrx.sw.sewage.dao.PointCalculationRuleDAO;

@Service
public class PointCalculationRuleService {
	private static final Logger logger = LoggerFactory.getLogger(PointCalculationRuleService.class);
	@Autowired
	private PointCalculationRuleDAO pointCalculationRuleDAO;
	@Autowired
	private JexlEngine jexlEngine;
	@Autowired
	private DeviceTimeDataDAO deviceTimeDataDAO;
	@Autowired
    private ObjectMapper objectMapper;
	@Autowired
	private GatherDevPointDAO gatherDevPointDAO;

	@Transactional
	public void calculate(String tenantId, String dataNode, String time, List<Map<String, Object>> dataList) {
		try {
			if (CollectionUtils.isEmpty(dataList)) {
				logger.debug("数据集为空，不需要逻辑点位计算");
				return;
			}
			// 查询所有业务逻辑点位规则
			List<PointCalculationRulePO> list = pointCalculationRuleDAO.listAll();
			if (CollectionUtils.isEmpty(list)) {
				logger.debug("逻辑点位规则为空，不需要业务逻辑点位计算");
				return;
			}
			// 将点位格式转为map
			Map<String, Object> dataMap = Maps.newHashMap();
			for(Map<String, Object> map : dataList) {
				dataMap.put(MapUtils.getString(map, "key"), map.get("val"));
			}

			List<Map<String, Object>> timeDataMapList = Lists.newArrayList();
			List<Map<String, Object>> devPointMapList = Lists.newArrayList();
			Map<String, Object> timeDataMap = null;
			Map<String, Object> devPointMap = null;
			Map<String, Object> jsonMap = Maps.newHashMap();
			// 循环执行所有的规则，后期可改为多线程执行模式
			for(PointCalculationRulePO po : list) {
				String variable = po.getVariable();
				String[] var = StringUtils.split(variable, ",");
				
				// 创建Jexl表达式变量上下文
				JexlContext jexlContext = new MapContext();
				boolean varFlag = false;// 是否条件不满足
				for(int i = 0;i < var.length;i++) {
					if(dataMap.get(var[i]) == null) {// 校验该表达式所需要的变量是否都存在于这包数据中
						varFlag = true;
						break;
					}
					jexlContext.set(var[i], dataMap.get(var[i]));// 循环为表达式变量赋值
				}
				if(varFlag) {// 跳出外部点位规则循环，重置条件参数
					varFlag = false;
					continue;
				}
				
				// 创建Jexl表达式解析器 
				JexlScript jexlScript = jexlEngine.createScript(po.getExpression());
				// 执行Jexl表达式，得到结果
				String result = jexlScript.execute(jexlContext) + "";
				jsonMap.put(po.getCode(), result);
				
				// 查询对应的点位id
				Long devId = gatherDevPointDAO.findIdByValue(po.getCode());
				
				// 组装插入实时表的数据
				timeDataMap = Maps.newHashMap();
				timeDataMap.put("devId", devId);
				timeDataMap.put("jsonVal", "'" + JSONObject.parseObject(objectMapper.writeValueAsString(jsonMap)) + "'");
				timeDataMap.put("createTime", LocalDateTime.now());
				timeDataMap.put("collectTime", LocalDateTimeUtils.stringToLocalDateTime(time));
				timeDataMapList.add(timeDataMap);
				
				// 组装修改点位表最新值
				devPointMap = Maps.newHashMap();
				devPointMap.put("id", devId);
				devPointMap.put("parValue", StringUtils.isNotBlank(result) ? Double.parseDouble(result) : null);
				devPointMap.put("collectTime", LocalDateTimeUtils.stringToLocalDateTime(time));
				devPointMapList.add(devPointMap);
			}
			// 批量新增计算得出的实时点位
			if(CollectionUtils.isNotEmpty(timeDataMapList)) {
				Map<String, Object> params = Maps.newHashMap();
			    params.put("list", timeDataMapList);
			    params.put("dataNode", dataNode);
			    deviceTimeDataDAO.batchInsert(params);
			}
			// 批量修改点位最新值
			if(CollectionUtils.isNotEmpty(devPointMapList)) {
				Map<String, Object> params = Maps.newHashMap();
			    params.put("list", devPointMapList);
			    params.put("dataNode", dataNode);
			    gatherDevPointDAO.batchUpdateByGatherDevPoiId(params);
			}
		} catch (Exception e) {
			logger.error("逻辑点位规则计算异常", e);
		}
	}
	
	public static void main(String[] args) {
		// 初始化Jexl构造器
        JexlBuilder jexlBuilder = new JexlBuilder();
        // 创建Jexl表达式引擎
        JexlEngine jexlEngine = jexlBuilder.create();
        // 创建Jexl表达式解析器
        JexlScript jexlScript = jexlEngine.createScript("if(GFJF2_GFJ4_DL_P>=10){return 1;}else{return 0;}");
        // 创建Jexl表达式变量上下文
        JexlContext jexlContext = new MapContext();
        jexlContext.set("GFJF2_GFJ4_DL_P", 9);
        // 执行Jexl表达式，得到结果
        Object result = jexlScript.execute(jexlContext);
        System.out.println("执行结果=" + result);
        
        /*组装点位数据*/
        Map<String, Object> dataMap = Maps.newHashMap();
        dataMap.put("GFJF2_GFJ4_DL_P", 180.6);
        /*组装点位计算规则*/
        List<PointCalculationRulePO> list = Lists.newArrayList();
        PointCalculationRulePO po = new PointCalculationRulePO();
		po.setCode("GFJF2_GFJ4_DL_P");
		po.setExpression("if(GFJF2_GFJ4_DL_P>=10){return 1;}else{return 0;}");
		po.setVariable("GFJF2_GFJ4_DL_P");
		list.add(po);
        
		po = new PointCalculationRulePO();
		po.setCode("GFJF2_GFJ1_QT_T");
		po.setExpression("if(GFJF2_GFJ1_QT_T>=10){return 1;}else{return 0;}");
		po.setVariable("GFJF2_GFJ1_QT_T");
		list.add(po);
        
		po = new PointCalculationRulePO();
		po.setCode("GFJF2_GFJ3_QT_T");
		po.setExpression("if(GFJF2_GFJ3_QT_T>=10){return 1;}else{return 0;}");
		po.setVariable("GFJF2_GFJ3_QT_T");
		list.add(po);
        /*测试*/
        for(PointCalculationRulePO t : list) {
        	String variable = t.getVariable();
			String[] var = StringUtils.split(variable, ",");
			
			// 创建Jexl表达式变量上下文
			jexlContext = new MapContext();
			boolean varFlag = false;
			for(int i = 0;i < var.length;i++) {
				if(dataMap.get(var[i]) == null) {// 校验该表达式所需要的变量是否都存在于这包数据中
					varFlag = true;
					break;
				}
				jexlContext.set(var[i], dataMap.get(var[i]));// 循环为表达式变量赋值
			}
			if(varFlag) {
				varFlag = false;
				continue;
			}
			// 创建Jexl表达式解析器 
			jexlScript = jexlEngine.createScript(t.getExpression());
			// 执行Jexl表达式，得到结果
			result = jexlScript.execute(jexlContext) + "";
			System.out.println(t.getCode() + "得到的值为：" + result);
        }
	}
}